2.5 Vehicle Miles Traveled
2.5.1 County-level Analysis
# for(year in 2011:2017){
# for(county in c("013")){
#
# print(paste0(county,"-",year))
#
# ca_lodes <-
# grab_lodes(
# state = "ca",
# year = year,
# lodes_type = "od",
# job_type = "JT01", #Primary Jobs
# segment = "S000",
# state_part = "main",
# agg_geo = "tract"
# )
#
# save(ca_lodes, file = paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/ca_lodes_",year,"_tract.Rdata"))
#
# county_tracts <-
# ca_tracts %>%
# filter(COUNTYFP == county)
#
# county_lodes_h <-
# ca_lodes[which(ca_lodes$h_tract %in% county_tracts$GEOID),]
#
# county_lodes_h_origin_centroids <-
# st_centroid(ca_tracts[which(ca_tracts$GEOID %in% county_lodes_h$h_tract),])
#
# county_lodes_h_dest_centroids <-
# st_centroid(ca_tracts[which(ca_tracts$GEOID %in% county_lodes_h$w_tract),])
#
# route <-
# 1:nrow(county_lodes_h) %>%
# map_dfr(function(row){
# print(row)
# route <- osrmRoute(
# src = county_lodes_h_origin_centroids[which(county_lodes_h_origin_centroids$GEOID %in% county_lodes_h[row,"h_tract"]),],
# dst = county_lodes_h_dest_centroids[which(county_lodes_h_dest_centroids$GEOID %in% county_lodes_h[row,"w_tract"]),],
# overview = FALSE
# ) %>%
# as.list() %>%
# as.data.frame()
# if(is_empty(route)){
# return(
# data.frame(
# duration = NA,
# distance = NA
# )
# )
# } else {return(route)}
# })
#
# county_lodes_h_route <-
# county_lodes_h %>%
# cbind(route)
#
# county_lodes_h_filter <-
# county_lodes_h_route %>%
# filter(duration < 180)
#
# save(county_lodes_h_route,county_lodes_h_filter, file = paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_lodes_",county,"_",year,"_tract.Rdata"))
# }
# }
# county_commute_vmt_tractmode <- NULL
#
# for(year in 2011:2017){
# for(county in c("013")){
# print(paste0(year,"-",county))
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_lodes_",county,"_",year,"_tract.Rdata"))
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/acs5_vars_",year,".Rdata"))
#
# travel_time_mode <-
# getCensus(
# name = "acs/acs5",
# vintage = year,
# region = "tract:*",
# regionin = paste0("state:06+county:",county),
# vars = "group(B08134)"
# ) %>%
# mutate(tract = paste0(state,county,tract)) %>%
# select_if(!names(.) %in% c("GEO_ID","state","county","NAME")) %>%
# dplyr::select(-c(contains("EA"),contains("MA"),contains("M"))) %>%
# gather(
# key = "variable",
# value = "estimate",
# -tract
# ) %>%
# mutate(
# label = acs_vars$label[match(variable,acs_vars$name)],
# time = # This extracts only the time information from our label.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# max(unlist(gregexpr('!!',x)))+2
# )
# }
# ),
# nchar(label)
# ),
# mode = # This extracts only the mode information from our label. It doesn't fully deal with double-counting, so some are further removed later on in a filter.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# unlist(gregexpr('!!',x))[length(unlist(gregexpr('!!',x)))-1]+2
# )
# }
# ),
# lapply(
# label,
# function(x){
# max(unlist(gregexpr('!!',x)))-1
# }
# )
# )
# ) %>%
# filter(!is.na(time)) %>% # This removes the grand total rows that are usually at the top of the ACS data.
# filter(!mode %in% c("Car, truck, or van","Car truck or van","Carpooled","Public transportation (excluding taxicab)")) %>% # This removes double-counted subtotals.
# dplyr::select(-variable,-label)
#
# travel_time_mode_summary <-
# travel_time_mode %>%
# group_by(tract,time) %>%
# summarize(
# jobs = sum(estimate),
# jobs_drovealone = sum(estimate[which(mode == "Drove alone")]),
# jobs_carpool2 = sum(estimate[which(mode == "In 2-person carpool")]),
# jobs_carpool3 = sum(estimate[which(mode == "In 3-or-more-person carpool")]),
# ) %>%
# mutate(
# vehicles_drovealone = jobs_drovealone,
# vehicles_carpool2 = jobs_carpool2/2,
# vehicles_carpool3 = jobs_carpool3/3,
# jobs_car = jobs_drovealone+jobs_carpool2+jobs_carpool3,
# jobs_carpool = jobs_carpool2+jobs_carpool3,
# vehicles = vehicles_drovealone,vehicles_carpool2,vehicles_carpool3,
# perc_jobs_car = jobs_car/jobs,
# perc_jobs_carpool = jobs_carpool/jobs,
# perc_vehicle = vehicles/jobs
# )
#
# county_lodes_h_mode <-
# county_lodes_h_filter %>%
# transmute(
# residence = h_tract,
# jobs = S000,
# duration = duration,
# person_miles = S000*as.numeric(distance)/1.60934,
# person_hours = S000*as.numeric(duration)/60
# ) %>%
# mutate(
# tier =
# case_when(
# duration < 10 ~ "Less than 10 minutes",
# duration < 15 ~ "10 to 14 minutes",
# duration < 20 ~ "15 to 19 minutes",
# duration < 25 ~ "20 to 24 minutes",
# duration < 30 ~ "25 to 29 minutes",
# duration < 35 ~ "30 to 34 minutes",
# duration < 45 ~ "35 to 44 minutes",
# duration < 60 ~ "45 to 59 minutes",
# TRUE ~ "60 or more minutes"
# )
# ) %>%
# left_join(
# travel_time_mode_summary %>%
# dplyr::select(
# tract,
# time,
# perc_jobs_car,
# perc_jobs_carpool,
# perc_vehicle
# ),
# by = c("residence" = "tract", "tier" = "time")
# ) %>%
# mutate(
# jobs_car = jobs*perc_jobs_car,
# jobs_carpool = jobs*perc_jobs_carpool,
# vehicles = jobs*perc_vehicle,
# vmt = person_miles*perc_vehicle
# )
#
# county_commute_vmt_tractmode <-
# rbind(county_commute_vmt_tractmode,
# data.frame(
# Year = year,
# County = county,
# person_miles = sum(county_lodes_h_mode$person_miles, na.rm=T),
# jobs = sum(county_lodes_h_mode$jobs, na.rm=T),
# jobs_car = sum(county_lodes_h_mode$jobs_car, na.rm=T),
# jobs_carpool = sum(county_lodes_h_mode$jobs_carpool, na.rm=T),
# vehicles = sum(county_lodes_h_mode$vehicles, na.rm = T),
# vmt = sum(county_lodes_h_mode$vmt, na.rm=T)
# )
# )
#
# save(county_commute_vmt_tractmode,file = "C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_commute_vmt_tractmode.Rdata")
# }
# }
load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_commute_vmt_tractmode.Rdata")
county_commute_vmt_tractmode %>%
ggplot(
aes(
x = Year,
y = vmt/jobs,
colour = County
)
) +
geom_line()
Figure 17: One-way commute miles per job by county, 2011 to 2017. Data from LODES.
# county_commute_vmt_countymode <- NULL
#
# for(year in 2011:2017){
# for(county in c("013")){
#
# print(paste0(year,"-",county))
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_lodes_",county,"_",year,"_tract.Rdata"))
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/acs1_vars_",year,".Rdata"))
#
# travel_time_mode <-
# getCensus(
# name = "acs/acs1",
# vintage = year,
# region = paste0("county:",county),
# regionin = "state:06",
# vars = "group(B08134)"
# ) %>%
# select_if(!names(.) %in% c("GEO_ID","state","NAME")) %>%
# dplyr::select(-c(contains("EA"),contains("MA"),contains("M"))) %>%
# gather(
# key = "variable",
# value = "estimate",
# -county
# ) %>%
# mutate(
# label = acs_vars$label[match(variable,acs_vars$name)],
# time = # This extracts only the time information from our label.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# max(unlist(gregexpr('!!',x)))+2
# )
# }
# ),
# nchar(label)
# ),
# mode = # This extracts only the mode information from our label. It doesn't fully deal with double-counting, so some are further removed later on in a filter.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# unlist(gregexpr('!!',x))[length(unlist(gregexpr('!!',x)))-1]+2
# )
# }
# ),
# lapply(
# label,
# function(x){
# max(unlist(gregexpr('!!',x)))-1
# }
# )
# )
# ) %>%
# filter(!is.na(time)) %>% # This removes the grand total rows that are usually at the top of the ACS data.
# filter(!mode %in% c("Car, truck, or van","Car truck or van","Carpooled","Public transportation (excluding taxicab)")) %>% # This removes double-counted subtotals.
# dplyr::select(-variable,-label)
#
# travel_time_mode_summary <-
# travel_time_mode %>%
# group_by(time) %>%
# summarize(
# jobs = sum(estimate),
# jobs_drovealone = sum(estimate[which(mode == "Drove alone")]),
# jobs_carpool2 = sum(estimate[which(mode == "In 2-person carpool")]),
# jobs_carpool3 = sum(estimate[which(mode == "In 3-or-more-person carpool")]),
# ) %>%
# mutate(
# vehicles_drovealone = jobs_drovealone,
# vehicles_carpool2 = jobs_carpool2/2,
# vehicles_carpool3 = jobs_carpool3/3,
# jobs_car = jobs_drovealone+jobs_carpool2+jobs_carpool3,
# jobs_carpool = jobs_carpool2+jobs_carpool3,
# vehicles = vehicles_drovealone,vehicles_carpool2,vehicles_carpool3,
# perc_jobs_car = jobs_car/jobs,
# perc_jobs_carpool = jobs_carpool/jobs,
# perc_vehicle = vehicles/jobs
# )
#
# county_lodes_h_mode <-
# county_lodes_h_filter %>%
# transmute(
# jobs = S000,
# duration = duration,
# person_miles = S000*as.numeric(distance)/1.60934,
# person_hours = S000*as.numeric(duration)/60
# ) %>%
# mutate(
# tier =
# case_when(
# duration < 10 ~ "Less than 10 minutes",
# duration < 15 ~ "10 to 14 minutes",
# duration < 20 ~ "15 to 19 minutes",
# duration < 25 ~ "20 to 24 minutes",
# duration < 30 ~ "25 to 29 minutes",
# duration < 35 ~ "30 to 34 minutes",
# duration < 45 ~ "35 to 44 minutes",
# duration < 60 ~ "45 to 59 minutes",
# TRUE ~ "60 or more minutes"
# )
# ) %>%
# left_join(
# travel_time_mode_summary %>%
# dplyr::select(
# time,
# perc_jobs_car,
# perc_jobs_carpool,
# perc_vehicle
# ),
# by = c("tier" = "time")
# ) %>%
# mutate(
# jobs_car = jobs*perc_jobs_car,
# jobs_carpool = jobs*perc_jobs_carpool,
# vehicles = jobs*perc_vehicle,
# vmt = person_miles*perc_vehicle
# )
#
# county_commute_vmt_countymode <-
# rbind(county_commute_vmt_countymode,
# data.frame(
# Year = year,
# County = county,
# person_miles = sum(county_lodes_h_mode$person_miles, na.rm=T),
# jobs = sum(county_lodes_h_mode$jobs, na.rm=T),
# jobs_car = sum(county_lodes_h_mode$jobs_car, na.rm=T),
# jobs_carpool = sum(county_lodes_h_mode$jobs_carpool, na.rm=T),
# vehicles = sum(county_lodes_h_mode$vehicles, na.rm = T),
# vmt = sum(county_lodes_h_mode$vmt, na.rm=T)
# )
# )
# }
# }
#
# save(county_commute_vmt_countymode, file = "C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_commute_vmt_countymode.Rdata")
# load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_commute_vmt_countymode.Rdata")
#
# county_commute_vmt_countymode %>%
# filter(jobs_car != 0) %>%
# ggplot(
# aes(
# x = Year,
# y = vmt/jobs,
# colour = County
# )
# ) +
# geom_line()
#
# load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_commute_vmt_tractmode.Rdata")
#
# load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_commute_vmt_countymode.Rdata")
#
# county_commute_vmt_compare <-
# rbind(
# county_commute_vmt_tractmode %>%
# mutate(type = "tract"),
# county_commute_vmt_countymode %>%
# mutate(type = "county")
# )
#
# county_commute_vmt_compare %>%
# filter(jobs_car != 0) %>%
# ggplot(
# aes(
# x = Year,
# y = vmt/jobs,
# linetype = type,
# colour = County
# )
# ) +
# geom_line()\(~\)
# county_modeshare <- NULL
#
# for(year in 2011:2017){
# for(county in county_neighbors$COUNTYFP){
#
# print(paste0(year,"-",county))
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/acs1_vars_",year,".Rdata"))
#
# travel_time_mode <-
# getCensus(
# name = "acs/acs1",
# vintage = year,
# region = paste0("county:",county),
# regionin = "state:06",
# vars = "group(B08134)"
# ) %>%
# select_if(!names(.) %in% c("GEO_ID","state","NAME")) %>%
# dplyr::select(-c(contains("EA"),contains("MA"),contains("M"))) %>%
# gather(
# key = "variable",
# value = "estimate",
# -county
# ) %>%
# mutate(
# label = acs_vars$label[match(variable,acs_vars$name)],
# time = # This extracts only the time information from our label.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# max(unlist(gregexpr('!!',x)))+2
# )
# }
# ),
# nchar(label)
# ),
# mode = # This extracts only the mode information from our label. It doesn't fully deal with double-counting, so some are further removed later on in a filter.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# unlist(gregexpr('!!',x))[length(unlist(gregexpr('!!',x)))-1]+2
# )
# }
# ),
# lapply(
# label,
# function(x){
# max(unlist(gregexpr('!!',x)))-1
# }
# )
# )
# ) %>%
# filter(!is.na(time)) %>% # This removes the grand total rows that are usually at the top of the ACS data.
# filter(!mode %in% c("Car, truck, or van","Car truck or van","Carpooled","Public transportation (excluding taxicab)")) %>% # This removes double-counted subtotals.
# dplyr::select(-variable,-label)
#
# travel_time_mode_summary <-
# travel_time_mode %>%
# summarize(
# jobs = sum(estimate),
# jobs_drovealone = sum(estimate[which(mode == "Drove alone")]),
# jobs_carpool2 = sum(estimate[which(mode == "In 2-person carpool")]),
# jobs_carpool3 = sum(estimate[which(mode == "In 3-or-more-person carpool")]),
# ) %>%
# mutate(
# vehicles_drovealone = jobs_drovealone,
# vehicles_carpool2 = jobs_carpool2/2,
# vehicles_carpool3 = jobs_carpool3/3,
# jobs_car = jobs_drovealone+jobs_carpool2+jobs_carpool3,
# jobs_carpool = jobs_carpool2+jobs_carpool3,
# vehicles = vehicles_drovealone,vehicles_carpool2,vehicles_carpool3,
# perc_jobs_car = jobs_car/jobs,
# perc_jobs_carpool = jobs_carpool/jobs,
# perc_vehicle = vehicles/jobs
# )
#
# county_modeshare <-
# county_modeshare %>%
# rbind(
# data.frame(
# year = year,
# county = county,
# jobs = travel_time_mode_summary$jobs,
# perc_jobs_car = travel_time_mode_summary$perc_jobs_car,
# perc_jobs_carpool = travel_time_mode_summary$perc_jobs_carpool,
# perc_vehicle = travel_time_mode_summary$perc_vehicle
# )
# )
# }
# }
#
# save(county_modeshare, file = "C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_modeshare.Rdata")
load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_modeshare.Rdata")
county_modeshare %>%
filter(county %in% c("077","001","013","067","099")) %>%
filter(jobs != 0) %>%
ggplot(
aes(
x = year,
y = perc_jobs_carpool/perc_jobs_car,
colour = county
)
) +
geom_line()
Figure 18: Percent of car-dependent commuters traveling by carpool, by county, 2011 to 2017. Data from LODES and ACS.
\(~\)
2.5.2 City-level Analysis
We isolated every pair of Stockton home blockgroups and work blockgroups and used the Open Source Routing Machine to compute a distance (in miles) and duration (and hours) for a one-way trip. The following graph shows the distribution of workplaces by distance from home for Stockton residents.
# for(year in 2011:2017){
#
# print(year)
#
# ca_lodes <-
# grab_lodes(
# state = "ca",
# year = year,
# lodes_type = "od",
# job_type = "JT01", #Primary Jobs
# segment = "S000",
# state_part = "main",
# agg_geo = "bg"
# )
#
# stockton_lodes_h <-
# ca_lodes[which(ca_lodes$h_bg %in% stockton_bgs_full$GEOID),]
#
# stockton_lodes_h_origin_centroids <-
# st_centroid(ca_bgs[which(ca_bgs$GEOID %in% stockton_lodes_h$h_bg),])
#
# stockton_lodes_h_dest_centroids <-
# st_centroid(ca_bgs[which(ca_bgs$GEOID %in% stockton_lodes_h$w_bg),])
#
# route <-
# 1:nrow(stockton_lodes_h) %>%
# map_dfr(function(row){
# print(row)
# route <- osrmRoute(
# src = stockton_lodes_h_origin_centroids[which(stockton_lodes_h_origin_centroids$GEOID %in% stockton_lodes_h[row,"h_bg"]),],
# dst = stockton_lodes_h_dest_centroids[which(stockton_lodes_h_dest_centroids$GEOID %in% stockton_lodes_h[row,"w_bg"]),],
# overview = FALSE
# ) %>%
# as.list() %>%
# as.data.frame()
# if(is_empty(route)){
# return(
# data.frame(
# duration = NA,
# distance = NA
# )
# )
# } else {return(route)}
# })
#
# stockton_lodes_h_route <-
# stockton_lodes_h %>%
# cbind(route)
#
# stockton_lodes_h_filter <-
# stockton_lodes_h_route %>%
# filter(duration < 180)
#
# save(stockton_lodes_h_route,stockton_lodes_h_filter, file = paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_lodes_",year,".Rdata"))
# }
load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_lodes_2017_tract.Rdata")
ggplot(
stockton_lodes_h_filter,
aes(
x = as.numeric(distance)/1.60934,
weight = S000
)
) +
geom_histogram(binwidth = 5) +
labs(title = "Workplace Commute Distance to Work for Stockton Employed Residents", x = "Commute Distance to Work, Miles", y = "Number of Residents")
Figure 19: Distribution of workplaces by distance from home for Stockton employed residents. Trips greater than 3 hours are removed. Data from LODES, 2017.
\(~\)
stockton_commute_avg <-
stockton_lodes_h_filter %>%
group_by(w_tract) %>%
summarize(
`Average Commute Time, Hours` = mean(duration, na.rm=T)
) %>%
left_join(ca_tracts, by = c("w_tract" = "GEOID")) %>%
st_as_sf()
map = mapview(stockton_commute_avg, zcol = "Average Commute Time, Hours", map.types = c("OpenStreetMap"), legend = TRUE, layer.name = 'Average Commute Time, Hours')
map@mapFigure 20: Tracts where Stockton residents work - average commute time, in hours. Data from LODES, 2017.
\(~\)
The graph above, and our subsequent analyses, focuses on destinations with average commute times of less than 3 hours, which eliminates the unrealistic commutes while preserving ~94% of reported commutes.
To conclude this section, we used LODES and ACS data from 2013-2017 to estimate the change in VMT over that time period. Since our specific VMT methodology includes many simplifying assumptions, it is perhaps most valuable to see the change in VMT using a constant methodology over time.
We estimated the total and average GHG emissions for Stockton workers commuting to each of the top 15 counties (filtering out counties further than 3 hours away). We made the following assumptions:
- For each origin-destination block group pair, we used ACS 1-yr 2017 data on commute mode by travel time for the origin block group to estimate a share of travelers commuting by single occupancy vehicle and by carpooling, and applied this factor to the count of jobs from LODES to estimate a total number of vehicle trips and vehicle mildes traveled (VMT).
- For carpool trips, we counted 2-person carpools as 1 vehicle for every 2 jobs, and 3-or-more-person carpools as 1 vehicle for every 3 jobs.
- For daily VMT, each vehicle was assumed to take 2 one-way trips.
- To convert daily VMT to annual VMT, the same annualization factor was used as ICLEI: 369.39. The factor appears to account for both expected reductions in VMT because of sick days, as well as expected increases in VMT because of chained trips.
- All vehicles were assumed to be passenger vehicles with an average mpg of 29.2 in 2017 and CO2e emissions of 303 g/mi (0.000334 tCO2e/mi), using data from the EPA Automotive Trends Report. Disregarding SUVs and trucks has the effect of underestimating emissions.
stockton_commute_vmt_bgmode <- NULL
# for(year in 2011:2017){
# print(year)
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_lodes_",year,".Rdata"))
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/acs5_vars_",year,".Rdata"))
#
# travel_time_mode <-
# getCensus(
# name = "acs/acs5",
# vintage = ifelse(
# year < 2013,
# 2013,
# year
# ),
# region = "block group:*",
# regionin = "state:06+county:077",
# vars = "group(B08134)"
# ) %>%
# mutate(bg = paste0(state,county,tract,block_group)) %>%
# select_if(!names(.) %in% c("GEO_ID","state","county","tract","block_group","NAME")) %>%
# dplyr::select(-c(contains("EA"),contains("MA"),contains("M"))) %>%
# gather(
# key = "variable",
# value = "estimate",
# -bg
# ) %>%
# mutate(
# label = acs_vars$label[match(variable,acs_vars$name)],
# time = # This extracts only the time information from our label.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# max(unlist(gregexpr('!!',x)))+2
# )
# }
# ),
# nchar(label)
# ),
# mode = # This extracts only the mode information from our label. It doesn't fully deal with double-counting, so some are further removed later on in a filter.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# unlist(gregexpr('!!',x))[length(unlist(gregexpr('!!',x)))-1]+2
# )
# }
# ),
# lapply(
# label,
# function(x){
# max(unlist(gregexpr('!!',x)))-1
# }
# )
# )
# ) %>%
# filter(!is.na(time)) %>% # This removes the grand total rows that are usually at the top of the ACS data.
# filter(!mode %in% c("Car, truck, or van","Car truck or van","Carpooled","Public transportation (excluding taxicab)")) %>% # This removes double-counted subtotals.
# dplyr::select(-variable,-label)
#
# travel_time_mode_summary <-
# travel_time_mode %>%
# group_by(bg,time) %>%
# summarize(
# jobs = sum(estimate),
# jobs_drovealone = sum(estimate[which(mode == "Drove alone")]),
# jobs_carpool2 = sum(estimate[which(mode == "In 2-person carpool")]),
# jobs_carpool3 = sum(estimate[which(mode == "In 3-or-more-person carpool")]),
# ) %>%
# mutate(
# vehicles_drovealone = jobs_drovealone,
# vehicles_carpool2 = jobs_carpool2/2,
# vehicles_carpool3 = jobs_carpool3/3,
# jobs_car = jobs_drovealone+jobs_carpool2+jobs_carpool3,
# jobs_carpool = jobs_carpool2+jobs_carpool3,
# vehicles = vehicles_drovealone,vehicles_carpool2,vehicles_carpool3,
# perc_jobs_car = jobs_car/jobs,
# perc_jobs_carpool = jobs_carpool/jobs,
# perc_vehicle = vehicles/jobs
# )
#
# stockton_lodes_h_mode <-
# stockton_lodes_h_filter %>%
# transmute(
# residence = h_bg,
# jobs = S000,
# duration = duration,
# person_miles = S000*as.numeric(distance)/1.60934,
# person_hours = S000*as.numeric(duration)/60
# ) %>%
# mutate(
# tier =
# case_when(
# duration < 10 ~ "Less than 10 minutes",
# duration < 15 ~ "10 to 14 minutes",
# duration < 20 ~ "15 to 19 minutes",
# duration < 25 ~ "20 to 24 minutes",
# duration < 30 ~ "25 to 29 minutes",
# duration < 35 ~ "30 to 34 minutes",
# duration < 45 ~ "35 to 44 minutes",
# duration < 60 ~ "45 to 59 minutes",
# TRUE ~ "60 or more minutes"
# )
# ) %>%
# left_join(
# travel_time_mode_summary %>%
# dplyr::select(
# bg,
# time,
# perc_jobs_car,
# perc_jobs_carpool,
# perc_vehicle
# ),
# by = c("residence" = "bg", "tier" = "time")
# ) %>%
# mutate(
# jobs_car = jobs*perc_jobs_car,
# jobs_carpool = jobs*perc_jobs_carpool,
# vehicles = jobs*perc_vehicle,
# vmt = person_miles*perc_vehicle
# )
#
# stockton_commute_vmt_bgmode <-
# rbind(stockton_commute_vmt_bgmode,
# data.frame(
# Year = year,
# person_miles = sum(stockton_lodes_h_mode$person_miles, na.rm=T),
# jobs = sum(stockton_lodes_h_mode$jobs, na.rm=T),
# jobs_car = sum(stockton_lodes_h_mode$jobs_car, na.rm=T),
# jobs_carpool = sum(stockton_lodes_h_mode$jobs_carpool, na.rm=T),
# vehicles = sum(stockton_lodes_h_mode$vehicles, na.rm = T),
# vmt = sum(stockton_lodes_h_mode$vmt, na.rm=T)
# )
# )
#
# save(stockton_commute_vmt_bgmode,file = "C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_bgmode.Rdata")
# }
load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_bgmode.Rdata")
stockton_commute_vmt_bgmode %>%
ggplot(
aes(
x = Year,
y = vmt/jobs
)
) +
geom_line()
Figure 21: One-way commute miles per job in Stockton, 2011 to 2017. Data from LODES.
# stockton_commute_vmt_tractmode <- NULL
#
# for(year in 2011:2017){
# print(year)
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_lodes_",year,"_tract.Rdata"))
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/acs5_vars_",year,".Rdata"))
#
# travel_time_mode <-
# getCensus(
# name = "acs/acs5",
# vintage = year,
# region = "tract:*",
# regionin = "state:06+county:077",
# vars = "group(B08134)"
# ) %>%
# mutate(tract = paste0(state,county,tract)) %>%
# select_if(!names(.) %in% c("GEO_ID","state","county","NAME")) %>%
# dplyr::select(-c(contains("EA"),contains("MA"),contains("M"))) %>%
# gather(
# key = "variable",
# value = "estimate",
# -tract
# ) %>%
# mutate(
# label = acs_vars$label[match(variable,acs_vars$name)],
# time = # This extracts only the time information from our label.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# max(unlist(gregexpr('!!',x)))+2
# )
# }
# ),
# nchar(label)
# ),
# mode = # This extracts only the mode information from our label. It doesn't fully deal with double-counting, so some are further removed later on in a filter.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# unlist(gregexpr('!!',x))[length(unlist(gregexpr('!!',x)))-1]+2
# )
# }
# ),
# lapply(
# label,
# function(x){
# max(unlist(gregexpr('!!',x)))-1
# }
# )
# )
# ) %>%
# filter(!is.na(time)) %>% # This removes the grand total rows that are usually at the top of the ACS data.
# filter(!mode %in% c("Car, truck, or van","Car truck or van","Carpooled","Public transportation (excluding taxicab)")) %>% # This removes double-counted subtotals.
# dplyr::select(-variable,-label)
#
# travel_time_mode_summary <-
# travel_time_mode %>%
# group_by(tract,time) %>%
# summarize(
# jobs = sum(estimate),
# jobs_drovealone = sum(estimate[which(mode == "Drove alone")]),
# jobs_carpool2 = sum(estimate[which(mode == "In 2-person carpool")]),
# jobs_carpool3 = sum(estimate[which(mode == "In 3-or-more-person carpool")]),
# ) %>%
# mutate(
# vehicles_drovealone = jobs_drovealone,
# vehicles_carpool2 = jobs_carpool2/2,
# vehicles_carpool3 = jobs_carpool3/3,
# jobs_car = jobs_drovealone+jobs_carpool2+jobs_carpool3,
# jobs_carpool = jobs_carpool2+jobs_carpool3,
# vehicles = vehicles_drovealone,vehicles_carpool2,vehicles_carpool3,
# perc_jobs_car = jobs_car/jobs,
# perc_jobs_carpool = jobs_carpool/jobs,
# perc_vehicle = vehicles/jobs
# )
#
# stockton_lodes_h_mode <-
# stockton_lodes_h_filter %>%
# transmute(
# residence = h_tract,
# jobs = S000,
# duration = duration,
# person_miles = S000*as.numeric(distance)/1.60934,
# person_hours = S000*as.numeric(duration)/60
# ) %>%
# mutate(
# tier =
# case_when(
# duration < 10 ~ "Less than 10 minutes",
# duration < 15 ~ "10 to 14 minutes",
# duration < 20 ~ "15 to 19 minutes",
# duration < 25 ~ "20 to 24 minutes",
# duration < 30 ~ "25 to 29 minutes",
# duration < 35 ~ "30 to 34 minutes",
# duration < 45 ~ "35 to 44 minutes",
# duration < 60 ~ "45 to 59 minutes",
# TRUE ~ "60 or more minutes"
# )
# ) %>%
# left_join(
# travel_time_mode_summary %>%
# dplyr::select(
# tract,
# time,
# perc_jobs_car,
# perc_jobs_carpool,
# perc_vehicle
# ),
# by = c("residence" = "tract", "tier" = "time")
# ) %>%
# mutate(
# jobs_car = jobs*perc_jobs_car,
# jobs_carpool = jobs*perc_jobs_carpool,
# vehicles = jobs*perc_vehicle,
# vmt = person_miles*perc_vehicle
# )
#
# stockton_commute_vmt_tractmode <-
# rbind(stockton_commute_vmt_tractmode,
# data.frame(
# Year = year,
# person_miles = sum(stockton_lodes_h_mode$person_miles, na.rm=T),
# jobs = sum(stockton_lodes_h_mode$jobs, na.rm=T),
# jobs_car = sum(stockton_lodes_h_mode$jobs_car, na.rm=T),
# jobs_carpool = sum(stockton_lodes_h_mode$jobs_carpool, na.rm=T),
# vehicles = sum(stockton_lodes_h_mode$vehicles, na.rm = T),
# vmt = sum(stockton_lodes_h_mode$vmt, na.rm=T)
# )
# )
#
# save(stockton_commute_vmt_tractmode,file = "C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_tractmode.Rdata")
# }
# load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_tractmode.Rdata")
#
# stockton_commute_vmt_tractmode %>%
# ggplot(
# aes(
# x = Year,
# y = vmt/jobs
# )
# ) +
# geom_line()
#
# stockton_commute_vmt_countymode <- NULL
#
# for(year in 2011:2017){
#
# print(year)
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_lodes_",year,"_tract.Rdata"))
#
# load(paste0("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/acs1_vars_",year,".Rdata"))
#
# travel_time_mode <-
# getCensus(
# name = "acs/acs1",
# vintage = year,
# region = "county:077",
# regionin = "state:06",
# vars = "group(B08134)"
# ) %>%
# select_if(!names(.) %in% c("GEO_ID","state","NAME")) %>%
# dplyr::select(-c(contains("EA"),contains("MA"),contains("M"))) %>%
# gather(
# key = "variable",
# value = "estimate",
# -county
# ) %>%
# mutate(
# label = acs_vars$label[match(variable,acs_vars$name)],
# time = # This extracts only the time information from our label.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# max(unlist(gregexpr('!!',x)))+2
# )
# }
# ),
# nchar(label)
# ),
# mode = # This extracts only the mode information from our label. It doesn't fully deal with double-counting, so some are further removed later on in a filter.
# substr(
# label,
# lapply(
# label,
# function(x){
# ifelse(
# length(unlist(gregexpr('!!',x)))<3,
# NA,
# unlist(gregexpr('!!',x))[length(unlist(gregexpr('!!',x)))-1]+2
# )
# }
# ),
# lapply(
# label,
# function(x){
# max(unlist(gregexpr('!!',x)))-1
# }
# )
# )
# ) %>%
# filter(!is.na(time)) %>% # This removes the grand total rows that are usually at the top of the ACS data.
# filter(!mode %in% c("Car, truck, or van","Car truck or van","Carpooled","Public transportation (excluding taxicab)")) %>% # This removes double-counted subtotals.
# dplyr::select(-variable,-label)
#
# travel_time_mode_summary <-
# travel_time_mode %>%
# group_by(time) %>%
# summarize(
# jobs = sum(estimate),
# jobs_drovealone = sum(estimate[which(mode == "Drove alone")]),
# jobs_carpool2 = sum(estimate[which(mode == "In 2-person carpool")]),
# jobs_carpool3 = sum(estimate[which(mode == "In 3-or-more-person carpool")]),
# ) %>%
# mutate(
# vehicles_drovealone = jobs_drovealone,
# vehicles_carpool2 = jobs_carpool2/2,
# vehicles_carpool3 = jobs_carpool3/3,
# jobs_car = jobs_drovealone+jobs_carpool2+jobs_carpool3,
# jobs_carpool = jobs_carpool2+jobs_carpool3,
# vehicles = vehicles_drovealone,vehicles_carpool2,vehicles_carpool3,
# perc_jobs_car = jobs_car/jobs,
# perc_jobs_carpool = jobs_carpool/jobs,
# perc_vehicle = vehicles/jobs
# )
#
# stockton_lodes_h_mode <-
# stockton_lodes_h_filter %>%
# transmute(
# jobs = S000,
# duration = duration,
# person_miles = S000*as.numeric(distance)/1.60934,
# person_hours = S000*as.numeric(duration)/60
# ) %>%
# mutate(
# tier =
# case_when(
# duration < 10 ~ "Less than 10 minutes",
# duration < 15 ~ "10 to 14 minutes",
# duration < 20 ~ "15 to 19 minutes",
# duration < 25 ~ "20 to 24 minutes",
# duration < 30 ~ "25 to 29 minutes",
# duration < 35 ~ "30 to 34 minutes",
# duration < 45 ~ "35 to 44 minutes",
# duration < 60 ~ "45 to 59 minutes",
# TRUE ~ "60 or more minutes"
# )
# ) %>%
# left_join(
# travel_time_mode_summary %>%
# dplyr::select(
# time,
# perc_jobs_car,
# perc_jobs_carpool,
# perc_vehicle
# ),
# by = c("tier" = "time")
# ) %>%
# mutate(
# jobs_car = jobs*perc_jobs_car,
# jobs_carpool = jobs*perc_jobs_carpool,
# vehicles = jobs*perc_vehicle,
# vmt = person_miles*perc_vehicle
# )
#
# stockton_commute_vmt_countymode <-
# rbind(stockton_commute_vmt_countymode,
# data.frame(
# Year = year,
# person_miles = sum(stockton_lodes_h_mode$person_miles, na.rm=T),
# jobs = sum(stockton_lodes_h_mode$jobs, na.rm=T),
# jobs_car = sum(stockton_lodes_h_mode$jobs_car, na.rm=T),
# jobs_carpool = sum(stockton_lodes_h_mode$jobs_carpool, na.rm=T),
# vehicles = sum(stockton_lodes_h_mode$vehicles, na.rm = T),
# vmt = sum(stockton_lodes_h_mode$vmt, na.rm=T)
# )
# )
# }
#
# save(stockton_commute_vmt_countymode, file = "C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_countymode.Rdata")
# load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_countymode.Rdata")
#
# stockton_commute_vmt_countymode %>%
# ggplot(
# aes(
# x = Year,
# y = vmt/jobs
# )
# ) +
# geom_line()
#
# load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_bgmode.Rdata")
#
# load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_tractmode.Rdata")
#
# load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_countymode.Rdata")
#
# stockton_commute_vmt_compare <-
# rbind(
# stockton_commute_vmt_bgmode %>%
# mutate(mode = "block group"),
# stockton_commute_vmt_tractmode %>%
# mutate(mode = "tract"),
# stockton_commute_vmt_countymode %>%
# mutate(mode = "county")
# )
#
# stockton_commute_vmt_compare %>%
# ggplot(
# aes(
# x = Year,
# y = vmt/jobs,
# linetype = mode
# )
# ) +
# geom_line()\(~\)
load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_commute_vmt_tractmode.Rdata")
load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/county_commute_vmt_tractmode.Rdata")
stockton_county_commute_vmt_compare <-
rbind(
stockton_commute_vmt_tractmode %>%
mutate(type = "stockton"),
county_commute_vmt_tractmode %>%
filter(County == "077") %>%
dplyr::select(-County) %>%
mutate(type = "sjc")
)
stockton_county_commute_vmt_compare %>%
ggplot(
aes(
x = Year,
y = jobs_carpool/jobs_car,
linetype = type
)
) +
geom_line()
Figure 22: Percent of car-dependent commuters traveling by carpool, SJC vs. Stockton, 2011 to 2017. Data from LODES and ACS.
\(~\)
stockton_commute_vmt_bgmode_table <-
stockton_commute_vmt_bgmode %>%
transmute(
Year = Year,
`Commute One-Way VMT` = prettyNum(round(vmt,-3), big.mark=","),
`Workers` = prettyNum(round(jobs,-3), big.mark=","),
`One-Way VMT/Workers` = round(vmt/jobs,1),
`% Car-Dependent Workers who Carpool` = paste0(round(jobs_carpool/jobs_car*100,1),"%")
)
kable(
stockton_commute_vmt_bgmode_table,
booktabs = TRUE,
caption = 'Stockton commute one-way VMT from 2011-2017. Data from LODES and ACS 1-yr.'
) %>%
kable_styling() %>%
scroll_box(width = "100%")| Year | Commute One-Way VMT | Workers | One-Way VMT/Workers | % Car-Dependent Workers who Carpool |
|---|---|---|---|---|
| 2011 | 1,652,000 | 96,000 | 17.2 | 18.1% |
| 2012 | 1,656,000 | 94,000 | 17.7 | 18.2% |
| 2013 | 1,767,000 | 99,000 | 17.8 | 18.3% |
| 2014 | 2,061,000 | 106,000 | 19.4 | 19.4% |
| 2015 | 2,049,000 | 112,000 | 18.4 | 19.3% |
| 2016 | 2,161,000 | 113,000 | 19.2 | 19.3% |
| 2017 | 2,386,000 | 117,000 | 20.4 | 18.6% |
\(~\)
The average one-way commute trip for the Stockton worker appears to have increased by 26% over the last 6 years. This could be explained by existing residents changing to jobs that are further and further away from home, where better employment opportunities can be found, and by new residents moving to Stockton to find affordable housing but retaining their faraway jobs.
To-do: - Forecast - Amenities VMT
load("C:/Users/derek/Google Drive/City Systems/Stockton Green Economy/LODES/stockton_lodes_2017.Rdata")
stockton_lodes_h_counties_ghg <-
stockton_lodes_h_mode %>%
st_set_geometry(NULL) %>%
mutate(
COUNTY = substr(workplace,3,5)
) %>%
group_by(COUNTY) %>%
summarise_at(
vars(jobs,person_miles,person_hours,vehicles,vmt),
sum, na.rm=T
) %>%
mutate(
perc_jobs = jobs/sum(jobs),
annual_vmt = vmt*2*369.39,
annual_ghg = annual_vmt*0.000334,
perc_ghg = annual_ghg/sum(annual_ghg),
avg_ghg = annual_ghg/jobs
) %>%
left_join(ca_counties, by = c("COUNTY" = "COUNTYFP")) %>%
st_as_sf() %>%
arrange(desc(annual_ghg))
stockton_lodes_h_counties_ghg_table <-
stockton_lodes_h_counties_ghg %>%
st_set_geometry(NULL) %>%
transmute(
County = NAME,
Jobs = prettyNum(round(jobs,-2),big.mark=","),
`Percent Jobs` = paste0(round(perc_jobs*100),"%"),
`VMT (millions)` = prettyNum(round(annual_vmt/1000000),big.mark=","),
`Total Annual GHG (tCO2e)` = prettyNum(round(annual_ghg,-3),big.mark=","),
`Percent Annual GHG` = paste0(round(perc_ghg*100),"%"),
`Average Annual GHG/worker (tCO2e)` = round(avg_ghg,1)
)
kable(
stockton_lodes_h_counties_ghg_table[1:15,],
booktabs = TRUE,
caption = 'Top 15 counties where Stockton residents work, GHG emissions. Data from LODES, 2017.'
) %>%
kable_styling() %>%
scroll_box(width = "100%")| County | Jobs | Percent Jobs | VMT (millions) | Total Annual GHG (tCO2e) | Percent Annual GHG | Average Annual GHG/worker (tCO2e) |
|---|---|---|---|---|---|---|
| San Joaquin | 69,200 | 59% | 369 | 123,000 | 18% | 1.8 |
| Alameda | 9,100 | 8% | 304 | 102,000 | 15% | 11.2 |
| Santa Clara | 5,700 | 5% | 244 | 81,000 | 12% | 14.2 |
| Sacramento | 8,900 | 8% | 209 | 70,000 | 10% | 7.8 |
| San Francisco | 3,100 | 3% | 143 | 48,000 | 7% | 15.5 |
| Contra Costa | 4,400 | 4% | 123 | 41,000 | 6% | 9.4 |
| San Mateo | 2,300 | 2% | 105 | 35,000 | 5% | 15.3 |
| Fresno | 1,300 | 1% | 92 | 31,000 | 5% | 23.2 |
| Stanislaus | 4,500 | 4% | 76 | 25,000 | 4% | 5.6 |
| Solano | 1,600 | 1% | 53 | 18,000 | 3% | 10.7 |
| Placer | 1,200 | 1% | 42 | 14,000 | 2% | 12.1 |
| Sonoma | 700 | 1% | 40 | 13,000 | 2% | 18.5 |
| Monterey | 500 | 0% | 36 | 12,000 | 2% | 24.6 |
| Yolo | 900 | 1% | 27 | 9,000 | 1% | 10.4 |
| Santa Cruz | 400 | 0% | 24 | 8,000 | 1% | 19.9 |
\(~\)
According to the table above, 59% percent of Stockton residents work in San Joaquin County and collectively contribute 18% of all commute GHGs. The next 14 counties comprise another 38% of Stockton residents, but they collectively contribute 76% of all commute GHGs. This significant difference comes down to difference in average commute distance to each county, which is directly related to average GHG emissions per worker, as seen in the following map. In a later section, we will explore opportunities to stimulate local job creation so that some of these long-distance commutes can be converted into local commutes, reducing both the toll on the environment and the tolls on health and well-being for Stockton residents.
stockton_lodes_h_counties_ghg_map <-
stockton_lodes_h_counties_ghg[1:15,] %>%
transmute(
County = NAME,
Jobs = prettyNum(jobs,big.mark=","),
`Percent Jobs` = round(perc_jobs,2),
VMT = prettyNum(round(vmt,0),big.mark=","),
`Total Annual GHG (tCO2e)` = round(annual_ghg,0),
`Percent Annual GHG` = round(perc_ghg,2),
`Average Annual GHG/worker (tCO2e)` = round(avg_ghg,2)
)
map = mapview(
stockton_lodes_h_counties_ghg_map,
zcol = "Average Annual GHG/worker (tCO2e)",
map.types = c("OpenStreetMap"),
legend = TRUE,
layer.name = 'Average Annual GHG/worker (tCO2e)'
)
map@mapFigure 23: Top 15 Counties where Stockton residents work - average GHG emissions from driving per worker. Data from LODES, 2017.
\(~\)
map = mapview(stockton_lodes_h_counties_ghg_map, zcol = "Total Annual GHG (tCO2e)", map.types = c("OpenStreetMap"), legend = TRUE, layer.name = 'Total Annual GHG (tCO2e)')
map@mapFigure 24: Top 15 Counties where Stockton residents work - annual GHG emissions from driving. Data from LODES, 2017.